#pragma once
#include "DJoint.h"
#include "../DBody.h"
#include "DJointFeedback.h"
#include "DJointGroup.h"
#include "../DOde.h"

namespace Skill
{
	namespace Ode
	{
		namespace Joints
		{
			void DJoint::CollectManagedMemory()
			{
				if(_Container)
					_Container->RemoveJoint(this);
				_Body1 = nullptr;
				_Body2 = nullptr;
				_UserData = nullptr;
				_World = nullptr;
				_Container = nullptr;
				_Feedback = nullptr;
			}
			DJoint::!DJoint()
			{
				if(_Free && _This && DOde::IsInitialized)
					dJointDestroy(_This);
				_This = nullptr;
				_Free = false;
				_Disposed = true;
			}

			DJoint::DJoint(DWorld^ world,DJointGroup^ container)
			{
				_World = world;
				_Container = container;
				if(_Container)
				{
					_Container->AddJoint(this);
				}
			}

			int DJoint::NumBodies::get()			
			{
				return dJointGetNumBodies(_This);
			}

			DWorld^ DJoint::World::get()
			{
				return _World;
			}

			DJointGroup^ DJoint::Container::get()
			{
				return _Container;
			}

			void DJoint::Attach(DBody^ body1, DBody^ body2)
			{
				_Body1 = body1;
				_Body2 = body2;
				dJointAttach(_This,_Body1? _Body1->_This : NULL, _Body2? _Body2->_This : NULL );
			}


			DBody^ DJoint::GetBody(int index)
			{
				if(index == 0)
					return _Body1;
				else if(index == 1)
					return _Body2;
				return nullptr;
			}
			DBody^ DJoint::Body1::get()
			{
				return _Body1;
			}
			DBody^ DJoint::Body2::get()
			{
				return _Body2;
			}
			Object^ DJoint::UserData::get()
			{
				return _UserData;
			}
			void DJoint::UserData::set(Object^ value)
			{
				_UserData = value;
			}

			DJointType DJoint::Type::get()
			{
				return (DJointType)dJointGetType(_This);
			}

			DJointFeedback^ DJoint::Feedback::get()
			{
				return _Feedback;
			}
			void DJoint::Feedback::set(DJointFeedback^ value)
			{
				_Feedback = value;
				dJointSetFeedback(_This,value->_This);
			}

			DJoint^ DJoint::GetConnectingJoint(DBody^ body1, DBody^ body2)
			{
				dJointID j = dConnectingJoint(body1->_This,body2->_This);
				if(j)
				{
					DIUnmanagedPointer^ p = DRegisteredObjects::Get(IntPtr(j));
					DJoint^ J = dynamic_cast<DJoint^>(p);
					return J;
				}
				return nullptr;
			}

			int DJoint::GetConnectingJointListCount(DBody^ body1, DBody^ body2)
			{
				dJointID* joints = nullptr;
				return dConnectingJointList(body1->_This,body2->_This,joints);
			}
			DJoint^ DJoint::GetConnectingJointList(DBody^ body1, DBody^ body2,int index)
			{
				dJointID* joints = nullptr;
				int count =  dConnectingJointList(body1->_This,body2->_This,joints);
				if(joints)
				{
					if(index >= 0 && index < count)
					{
						DIUnmanagedPointer^ p = DRegisteredObjects::Get(IntPtr(joints[index]));
						DJoint^ J = dynamic_cast<DJoint^>(p);
						return J;
					}
				}
				return nullptr;
			}
			bool DJoint::AreConnected(DBody^ body1, DBody^ body2)
			{
				return dAreConnected(body1->_This,body2->_This) == 1;
			}
			bool DJoint::AreConnectedExcluding(DBody^ body1, DBody^ body2,DJointType joint_type)
			{
				return dAreConnectedExcluding(body1->_This,body2->_This,(int)joint_type) == 1;
			}
		}
	}
}